package com.farm.system.service.impl;

import com.farm.constant.MessageConstant;
import com.farm.system.dao.RoleMapper;
import com.farm.system.dao.UserMapper;
import com.farm.system.pojo.User;
import com.farm.system.service.UserService;
import com.farm.util.MD5Utils;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import tk.mybatis.mapper.entity.Example;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 用户实现类
 *
 * @author Chengfei
 * @date 2020/10/10
 */
@Service
@Transactional
public class UserServiceImpl implements UserService {

    //设置重置密码
    private static final String RESET_PASSWORD = "123456";

    @Autowired
    private UserMapper userMapper;
    @Autowired
    private RoleMapper roleMapper;
    @Autowired
    private RedisTemplate redisTemplate;

    /**
     * 查询所有
     *
     * @return 用户集合
     */
    @Override
    public List<User> findAll() {
        List<User> userList = userMapper.selectAll();

        //判断数据有效性
        if (userList == null || userList.size() <= 0) {
            throw new RuntimeException(MessageConstant.SELECT_ALL_USER_FAIL);
        }

        //处理密码,不展示密文
        for (User user : userList) {
            user.setPassword(null);
        }

        return userList;
    }

    /**
     * 分页查询
     *
     * @param page      页码
     * @param size      大小
     * @param searchMap 条件
     * @return 用户集合
     */
    @Override
    public Page<User> findPageByCondition(Integer page, Integer size, Map<String, Object> searchMap) {

        //开启分页
        PageHelper.startPage(page, size);

        //调用方法添加条件
        Example example = createExample(searchMap);
        List<User> userList = userMapper.selectByExample(example);

        //判断数据是否有效
        if (userList == null || userList.size() <= 0) {
            throw new RuntimeException(MessageConstant.SELECT_USER_FAIL);
        }

        //处理密码,不展示密文
        for (User user : userList) {
            user.setPassword(null);
        }

        return (Page<User>) userList;
    }

    /**
     * 条件构造器
     *
     * @param searchMap 条件
     * @return
     */
    public Example createExample(Map<String, Object> searchMap) {
        Example example = new Example(User.class);
        Example.Criteria criteria = example.createCriteria();

        //判断条件数据是否有效
        if (searchMap != null && searchMap.size() > 0) {

            //判断用户名是否存在,存在添加用户名作为模糊查询条件
            if (StringUtils.isNotBlank((String) searchMap.get("name"))) {
                criteria.andLike("name", "%" + searchMap.get("name") + "%");
            }
            //判断登录名是否存在,存在添加登录名作为模糊查询条件
            if (StringUtils.isNotBlank((String) searchMap.get("username"))) {
                criteria.andLike("username", "%" + searchMap.get("username") + "%");
            }
            //判断电话是否存在,存在则添加作为模糊查询条件
            if (StringUtils.isNotBlank((String) searchMap.get("phone"))) {
                criteria.andLike("phone", "%" + searchMap.get("phone") + "%");
            }
            //判断邮箱是否存在,存在则添加作为模糊查询条件
            if (StringUtils.isNotBlank((String) searchMap.get("email"))) {
                criteria.andLike("email", "%" + searchMap.get("email") + "%");
            }
            //状态是否存在,存在则添加作为查询状态
            if (StringUtils.isNotBlank((String) searchMap.get("status"))) {
                criteria.andEqualTo("status", searchMap.get("status"));
            }
        }
        return example;
    }


    /**
     * 添加用户及用户角色中间表
     *
     * @param user    用户
     * @param roleIds 角色id数组
     */
    @Override
    public void add(User user, Integer[] roleIds) {
        //判断User数据是否有效
        if (user == null) {
            throw new RuntimeException(MessageConstant.ADD_USER_FAIL);
        }

        //先查询用户名是否存在,存在返回提示
        boolean flag = isExist(user.getUsername());
        if (flag) {
            throw new RuntimeException(MessageConstant.USER_EXIST_SUCCESS);
        }

        //设置初始密码
        String bCryptPassword = MD5Utils.BCrypt(RESET_PASSWORD);
        user.setPassword(bCryptPassword);

        //向用户表中添加用户
        userMapper.insertSelective(user);

        //向用户-角色表中添加数据
        setUserIdAndRoleId(user.getId(), roleIds);
    }

    //根据用户登录名判断用户是否存在
    private boolean isExist(String username) {
        User user = new User();
        user.setUsername(username);

        //用户存在返回true,不存在返回false
        return userMapper.select(user).size() > 0;
    }

    /**
     * 根据用户id逻辑删除
     *
     * @param userId 用户id
     */
    @Override
    public void delete(Integer userId) {
        User user = userMapper.selectByPrimaryKey(userId);
        //判断用户是否存在
        if (user == null) {
            throw new RuntimeException(MessageConstant.DELETE_USER_FAIL);
        }
        //创建一个用户,用于更新数据
        User userInfo = new User();
        //封装id和status
        userInfo.setId(user.getId());
        userInfo.setStatus("0");

        //逻辑删除用户,将用户状态修改为停用
        userMapper.updateByPrimaryKeySelective(userInfo);
    }

    /**
     * 更新用户及用户角色中间表
     *
     * @param user    用户
     * @param roleIds 角色id数组
     */
    @Override
    public void update(User user, Integer[] roleIds) {
        //判断User数据是否有效
        if (user == null) {
            throw new RuntimeException(MessageConstant.UPDATE_USER_FAIL);
        }
        //删除用户-角色中间表
        userMapper.deleteAssociation(user.getId());

        //添加用户-角色中间表
        setUserIdAndRoleId(user.getId(), roleIds);

        //更新用户
        userMapper.updateByPrimaryKeySelective(user);
    }

    /**
     * 重置密码
     *
     * @param userId 用户id
     */
    @Override
    public void resetPassword(Integer userId) {
        //根据用户id查询用户
        User user = userMapper.selectByPrimaryKey(userId);
        //判断用户是否为空
        if (user == null) {
            throw new RuntimeException(MessageConstant.RESET_USER_PASSWORD_FAIL);
        }

        //加密密码
        String bCryptPassword = MD5Utils.BCrypt(RESET_PASSWORD);

        //封装数据
        User userInfo = new User();
        userInfo.setId(userId);
        userInfo.setPassword(bCryptPassword);
        //更新用户信息
        userMapper.updateByPrimaryKeySelective(userInfo);

    }


    /**
     * 登录
     *
     * @param username 登录名
     * @param password 密码
     * @return
     */
    @Override
    public User login(String username, String password) {

        //从redis中取出,当前登录者次数,判断是否登录
        String countStr = (String) redisTemplate.opsForValue().get(username);
        if (countStr == null) {
            //设置有效时间为2个小时,统计登录失败次数
            redisTemplate.opsForValue().set(username, 0, 2, TimeUnit.HOURS);
        } else if (Integer.parseInt(countStr) == 5) {
            //在两个小时内,登录失败次数等于5次,锁定账号
            this.accountLock(username);
            redisTemplate.opsForValue().increment(username);
            return null;
        } else if (Integer.parseInt(countStr) > 5) {
            //失败次数大于5次,直接返回失败
            return null;
        }

        //判断数据是否有效
        if (StringUtils.isNotBlank(username) || StringUtils.isNotBlank(password)) {
            //根据登录名查询用户
            User userInfo = new User();
            userInfo.setUsername(username);
            User user = userMapper.selectOne(userInfo);
            //判断用户是否存在,不存在,直接返回登录失败
            if (user != null) {
                //校验密码是否相等
                boolean flag = MD5Utils.myMatches(password, user.getPassword());
                //密码检验成功,登录成功
                if (flag) {
                    //登录成功 生成jwt令牌 返回前端
                    return user;
                }
            }
        }

        //登录失败 登录失败次数加1
        redisTemplate.opsForValue().increment(username);
        return null;
    }

    /**
     * 锁定账号
     *
     * @param username 登录名
     */
    private void accountLock(String username) {
        //判断用户名是否有效
        if (StringUtils.isBlank(username)) {
            return;
        }

        //根据用户名查询用户
        User userInfo = new User();
        userInfo.setUsername(username);
        User user = userMapper.selectOne(userInfo);
        //判断用户是否存在 ,存在锁定账号 status改为0 停用状态
        if (user != null) {
            userInfo.setId(user.getId());
            userInfo.setStatus("0");
            userInfo.setUsername(null);
            userMapper.updateByPrimaryKeySelective(userInfo);
        }

    }

    /**
     * 恢复账号
     *
     * @param userId 用户id
     */
    @Override
    public void renew(Integer userId) {
        User user = new User();
        user.setId(userId);
        user.setStatus("1");
        //更新用户
        userMapper.updateByPrimaryKeySelective(user);

    }

    /**
     * 添加用户-角色表
     *
     * @param userId  用户id
     * @param roleIds 角色id数组
     */
    public void setUserIdAndRoleId(Integer userId, Integer[] roleIds) {
        //判断角色数组是否有效
        if (roleIds == null || roleIds.length <= 0) {
            return;
        }
        //添加用户-角色表
        for (Integer roleId : roleIds) {
            userMapper.setUserIdAndRoleId(userId, roleId);
        }

    }


}
